package org.oos.dao.lists.impl;

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.oos.atom.AtomEntity;
import org.oos.atom.entries.ReviewEntry;
import org.oos.atom.impl.AtomFeed;
import org.oos.dao.Dao;
import org.oos.dao.exceptions.ReadException;
import org.oos.dao.options.PageOptions;

import static org.oos.dao.options.OptionsMap.FINDERS.*;
import org.oos.lists.DynamicList;
import org.oos.lists.SortableList;
import org.oos.util.Log;

/**
 * 
 * 
 * 
 * @author pablo.gonzalez@11870.com
 * 
 * @param <Entity>
 * @param <Feed>
 */
public class ReadOnlyDynamicList<Entity extends AtomEntity, Feed extends AtomFeed<Entity>>
		extends AbstractList<Entity> implements DynamicList<Entity>, SortableList<Entity> {

	private static final long serialVersionUID = 3873304282632821435L;

	// protected Feed firstFeed;
	protected int totalSize = -1;
	protected int basePageSize = 0;
	protected List<Entity> buffer = new ArrayList<Entity>();
	protected Dao<Entity, Feed> dao;
	private List<Entity> all;

	public static final int MAX_FEED_SIZE = 200;

	/**
	 * 
	 * Create a new ReadOnly List from the provided feed (first page) as well a
	 * {@link Dao} to provide the following pages.
	 * 
	 * @param dao
	 * @param feed
	 */
	public ReadOnlyDynamicList(Dao<Entity, Feed> dao, Feed feed) {
		super();
		if (feed.getEntries() != null) {
			this.totalSize = feed.getTotalResults();
			this.basePageSize = feed.getItemsPerPage();
			this.buffer.addAll(feed.getEntries());
		}
		this.dao = dao;
	}

	@Override
	public List<Entity> getAll() {
		if (all == null) {
			all = new ArrayList<Entity>(this);
		}
		return all;
	}

	@Override
	public void loadAll() throws ReadException {
		buffer.clear();
		int pageCount = totalSize / MAX_FEED_SIZE;
		if (totalSize % MAX_FEED_SIZE != 0) {
			pageCount += 1;
		}
		PageOptions pageOptions = PAGE_OPTIONS.get(dao.getOptions());
		int originalPageSize = pageOptions.getPageSize();
		pageOptions.setPageSize(MAX_FEED_SIZE);
		for (int i = 1; i <= pageCount; i++) {
			List<Entity> entries = dao.readFeed(i).getEntries();
			if (entries != null) {
				buffer.addAll(entries);
			}
		}
		pageOptions.setPageSize(originalPageSize);
	}

	@Override
	public Entity get(int index) {
		try {
			if (index < 0 || index >= totalSize) {
				throw new IndexOutOfBoundsException();
			}

			int pageSize = basePageSize;

			if (all != null) {
				return all.get(index);
			}

			if (index >= buffer.size()) {
				while (buffer.size() <= index) {
					int page = ((buffer.size() + 1) / pageSize) + 1;
					List<Entity> entries = dao.readFeed(page).getEntries();
					if (entries != null) {
						buffer.addAll(entries);
					} else {
						// we are in trouble if this line is reached
						throw new ReadException("Couldn't load all the items in ReadOnlyDynamicList");
					}
				}
			}
			return buffer.get(index);
		} catch (ReadException e) {
			Log.e(e);
			return null;
//			throw new RuntimeException(e);
		}
	}

	@Override
	public int size() {
		return totalSize;
	}

	@SuppressWarnings("unchecked")
	@Override
	public ReadOnlyDynamicList<Entity, Feed> clone()
			throws CloneNotSupportedException {
		return (ReadOnlyDynamicList<Entity, Feed>) super.clone();
	}

	@Override
	public void sort() {
		sort(new Comparator<Entity>() {
			@Override
			public int compare(Entity r1, Entity r2) {
				if (r1 instanceof ReviewEntry && r2 instanceof ReviewEntry) {
					ReviewEntry entry1 = (ReviewEntry) r1;
					ReviewEntry entry2 = (ReviewEntry) r2;
					String name1 = entry1.getTitle().getValue().toLowerCase();
					String name2 = entry2.getTitle().getValue().toLowerCase();
					return name1.compareTo(name2);
				} else {
					throw new RuntimeException("Both entities must be of the type AtomEntity");
				}
				
			}
		});
		
	}

	@Override
	public void sort(Comparator<Entity> comparator) {
		Collections.sort(this.buffer, comparator);
	}

}
